/**
 * 
 */
package kulstats;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;

/**
 * @author steven
 *
 */
public class MilestoneManager {
	//private DAO dao;
	private static final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	private static final CalculatePoints calcPts = new CalculatePoints();
	
	public MilestoneManager() { //DAO dao) {
		//this.dao = dao;
	}
	
	/*
	 * @param key the user'key
	 * @param milestone the milestone to be saved
	 */
	public boolean saveMilestone(Milestone milestone, Key key){
		
		if(!verifyAlreadySaved(milestone,key)) {
			Entity mst = new Entity("Milestone", key);
			mst.setProperty("StartDate", milestone.getStartDate());
			mst.setProperty("StopDate", milestone.getStopDate());
			mst.setProperty("Predefined", milestone.isPredefined());
			mst.setProperty("Course", milestone.getCourse().getCourseID());
			mst.setProperty("Hours", milestone.getHours());
			mst.setProperty("Reached", milestone.isReached());
			mst.setProperty("Points", milestone.getPoints());
			datastore.put(mst);
			return true;
		}
		else {
			return false;
		}
	}
	public boolean verifyAlreadySaved(Milestone milestone,Key key) {
		String courseID = milestone.getCourse().getCourseID();
		Milestone mst = getMilestoneByCourse(key,courseID);
		if(mst!=null) {
			return true;
		}
		return false;
	}

	/*
	 * @return returns all the milestone of the user(by key)
	 * @param key the user'key
	 */
	public List<Milestone> getMilestones(Key key){
		Query q = new Query("Milestone");
		q.setAncestor(key);
		List<Entity> pq = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
		
		List<Milestone> list = new ArrayList<Milestone>();
		for (int i = 0; i < pq.size(); i++)
		{
			Map<String, Object> props = pq.get(i).getProperties();
			CourseManager courseManager = Registry.courseManager();
			Course course = courseManager.getCourseByID((String)props.get("Course"));
			Milestone mst = new Milestone((Date)props.get("StartDate"), (Date)props.get("StopDate")
					,(Boolean)props.get("Predefined"), course
					,(Integer)((Long)props.get("Hours")).intValue(), (Boolean)props.get("Reached"));
			int points = calculatePoints(mst);
			mst.setPoints(points);
			list.add(mst);
		}
		
		
		return list;
	}

	/*
	 * @return returns all the milestone of the user(by key)
	 * @param key the user'key
	 */
	public List<Milestone> getMilestones(Key key,String courseID){
		Query q = new Query("Milestone");
		q.setAncestor(key);
		q.addFilter("Course", Query.FilterOperator.EQUAL, courseID);;
		List<Entity> pq = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
		
		List<Milestone> list = new ArrayList<Milestone>();
		for (int i = 0; i < pq.size(); i++)
		{
			Map<String, Object> props = pq.get(i).getProperties();
			CourseManager courseManager = Registry.courseManager();
			Course course = courseManager.getCourseByID((String)props.get("Course"));
			Milestone mst = new Milestone((Date)props.get("StartDate"), (Date)props.get("StopDate")
					,(Boolean)props.get("Predefined"), course
					,(Integer)((Long)props.get("Hours")).intValue(), (Boolean)props.get("Reached"));
			int points = calculatePoints(mst);
			mst.setPoints(points);
			list.add(mst);
		}
		return list;
	}
	
	
	/*
	 * @return returns if all the milestones of the user are succesful
	 * @param user the user who's milestones are checked
	 */
	public boolean verifyMilestones(User user)
	{
		boolean b= true;
		Key userKey = user.getKey();
		List<Milestone> listMilestones = getMilestones(userKey);
		Iterator<Milestone> it = listMilestones.iterator();
		while (it.hasNext()) {
			Milestone mst = it.next();
			boolean bool = verifyMilestone(mst, user);
			if(!bool) {
				b=false;
			}
		}
		return b;
	}
	/*
	 * @return boolean returns if the milestone of the user is successful
	 * @param milestone the milestone to be checked
	 * @param userKey the key of the user
	 */
	public boolean verifyMilestone(Milestone milestone,User user)
	{
		boolean b = false;
		Key userKey = user.getKey();
		
		boolean bool =  milestone.isReached();
		if(bool) {
			b=true;
		}
		else {
			double progress = getProgress(milestone,userKey);
			if(progress>=1) {
				b=true;
				milestone.setReached(true);
				saveMilestone(milestone,userKey);
				int points = calculatePoints(milestone);
				user.updatePoints(points);
			}
		}
		
		
		return b;
	}
	/*
	 * @return double returns the amount of time spend on the course of the milestone 
	 * divided by the set goal of the milestone
	 * @param milestone the milestone to be checked
	 * @param userKey the key of the user 
	 */
	public double getProgress(Milestone milestone, Key userKey)
	{
		ActivityManager actMan = Registry.activityManager();
		Date StopDateMilestone = milestone.getStopDate();
		Date StartDateMilestone = milestone.getStartDate();
		Date now = new Date();
		Course course = milestone.getCourse();
		String courseID = course.getCourseID();
		int goal = milestone.getHours()*60*60*1000;
		long time =0;
		List<Activity> listAct = actMan.getActivities(userKey,courseID);
		Iterator<Activity> it = listAct.iterator();
		while (it.hasNext()) {
				Activity act = it.next();
				Date stopAct = act.getStopDate();
				Date startAct = act.getStartDate();
				
				if(stopAct != null && stopAct.before(StopDateMilestone)) {
					if(startAct.after(StartDateMilestone)) {
						time+= stopAct.getTime() - startAct.getTime();
					}
				}
		}
		double studiedTime = time;
		double progress = studiedTime/(double)goal;
		return progress;
	}
	/*
	 * @param user the user who's unfinished milestone are retreved
	 * @return unfinishedMilestones the unfinished milestones
	 */
	public Map<String, LinkedList<Double>> getUnfinishedMilestones(User user){
		
		Map<String, LinkedList<Double>> unfinishedMilestones = new HashMap<String, LinkedList<Double>>();
		Key userKey = user.getKey();
		
		List<Milestone> listMilestones = getMilestones(userKey);
		if(!listMilestones.isEmpty()) {
		Iterator<Milestone> it = listMilestones.iterator();
		while (it.hasNext()) {
			Milestone mst = it.next();
			boolean bool = verifyMilestone(mst, user);
			if(!bool) {
				double progress = getProgress(mst,userKey);
				String course = mst.getCourse().getName();
				if(progress>=1) {
					progress = (double) 1;
				}
				LinkedList<Double> list = new LinkedList<Double>();
				list.add(progress);
				list.add((double)mst.getHours());
				unfinishedMilestones.put(course, list);
			}
		 }
		}
		return unfinishedMilestones;
	}
	
	public Milestone getMilestoneByCourse(Key key,String course) {
		
		List<Milestone> list = getMilestones(key,course);
		/*Iterator it = list.iterator();
		
		while(it.hasNext()) {
			Milestone mst = (Milestone)it.next();
			System.out.print("getMilestoneByCourse : " + key );
			String mstString = mst.getCourse().getCourseID();
			if(course.equals(mstString)) {
				milestone = mst;
			}
		}*/
		return (list != null && !list.isEmpty()) ? list.get(0) : null;
	}
	public int calculatePoints(Milestone milestone)
	{
	
		int points = calcPts.calculateMilestonePoints(milestone);
		return points;
	}
}
